#pragma once

#include "Common.hpp"
#include "Log.hpp"
#include "Loop.hpp" 
using TaskFunc = std::function<void()>;
using ReleaserFunc = std::function<void()>;

// 定时器任务
class TimerTask{
public:
    TimerTask(uint64_t id, uint32_t delay, const TaskFunc& cb):
        _id(id),_timeout(delay),_cb(cb),_canceled(false)
    {}

    ~TimerTask() { 
        if (!_canceled) {
            // std::thread(_cb).detach(); // 不能异步执行回调
            _cb();
        }
        // if (!_canceled) _cb();  // 用这个的话 _cb 就会先执行, 否则后执行
        _release(); 
    }

    void SetRelease(const ReleaserFunc& release){_release = release;}
    void Cancel() {_canceled = true;} // 取消定时任务
    uint32_t DelayTime() const { return _timeout; }

private:
    uint64_t _id;           // 定时器任务 id
    uint32_t _timeout;      // 定时任务超时时间
    bool _canceled;         // 是否取消定时任务(true: 取消)
    TaskFunc _cb;           // 定时器对象要执行的定时任务
    ReleaserFunc _release;  // 用于删除 TimerWheel 中保存的定时器对象信息
};

// 定时器轮
class TimerWheel{
private:
    using WeakTask = std::weak_ptr<TimerTask>; // 辅助 shared_ptr 解决循环引用问题
    using PtrTask = std::shared_ptr<TimerTask>;
    const int capacity = 60; // 定时器轮的大小 -- 最大延迟时间

    void RemoveTimer(uint64_t id){
        auto it = _timers.find(id);
        if(it != _timers.end()){
            _timers.erase(it); // 删除定时器对象
        }
    }

    static int CreateTimerfd(){
        int timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
        if (timerfd < 0) {
            LOG_ERROR("Create timerfd error");
            abort();
        }

        struct itimerspec itime;
        // 设置第一次超时间隔时间为 1 s
        itime.it_value.tv_sec = 1;
        itime.it_value.tv_nsec = 0;
    
        // 设置第一次超时后 每次超时时间间隔为 1 s
        itime.it_interval.tv_sec = 1;
        itime.it_interval.tv_nsec = 0;
        timerfd_settime(timerfd, 0, &itime, nullptr); // 设置定时器

        return timerfd;
    }

    int ReadTimerfd(){
        uint64_t times = 0;
        // 有可能因为其他描述符的事件处理花费事件比较长，然后在处理定时器描述符事件的时候，有可能就已经超时了很多次
        // read读取到的数据times就是从上一次read之后超时的次数
        ssize_t ret = read(_timerfd, &times, sizeof(times));
        if (ret < 0) {
            LOG_ERROR("READ TIMERFD ERROR");
            abort(); // 退出程序
        }
        return times;
    }

    // 3. 执行定时任务 
    void RunTimerTask(){
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear(); // 清空当前 tick 的任务
    }

    void OnTime(){
        //根据实际超时的次数，执行对应的超时任务
        int times = ReadTimerfd(); // 读取定时器文件描述符, 触发事件
        for(int i = 0; i < times; ++i){
            RunTimerTask(); // 执行定时任务
        }
    }

    // 1. 添加定时任务
    void TimerAddInLoop(uint64_t id, uint32_t delay, const TaskFunc& cb){  
        PtrTask pt(new TimerTask(id, delay, cb));
        pt->SetRelease(std::bind(&TimerWheel::RemoveTimer, this, id));
        
        int pos = (_tick + delay) % _capacity; // 计算定时器任务在轮子上的位置
        _wheel[pos].push_back(pt); // 将定时器任务添加到轮子上
        _timers[id] = WeakTask(pt); // 不能用 shared_ptr, 否则永久有shared_ptr 来管理, 计数不归0         
    }   
    

    // 4. 刷新/延迟 定时任务
    void TimerRefreshInLoop(uint64_t id) {
        // 1, 通过保存定时器对象的 weak_ptr 来获取定时器对象 添加到轮子中
        auto it = _timers.find(id);
        if (it == _timers.end())  // 没找到定时任务, 无法刷新和延迟
            return;
        
        PtrTask pt = it->second.lock(); // lock获取weak_ptr管理的对象对应的shared_ptr

        int delay = pt->DelayTime();
        
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
    }

    // 5. 取消定时任务
    void TimerCanceInLoop(uint64_t id) {
        auto it = _timers.find(id);
        if(it == _timers.end()) return ;

        PtrTask pt = it->second.lock(); // lock获取weak_ptr管理的对象对应的shared_ptr
        // 如果weak_ptr管理的对象已经被销毁（即引用计数为0），lock()会返回一个空的shared_ptr
        // 如果对象仍然存在，lock()会返回一个有效的shared_ptr，指向该对象

        if(pt) pt->Cancel(); // 取消定时任务
    }

public:
    TimerWheel(EventLoop *loop):_capacity(capacity),_tick(0),_wheel(_capacity),_loop(loop), _timerfd(CreateTimerfd()), _timer_channel(new Channel(_loop, _timerfd))
    {
        _timer_channel->SetReadCallback(std::bind(&TimerWheel::OnTime, this)); // 设置定时器可读事件回调函数
        _timer_channel->EnableRead(); // 启动读事件监控
    }

    // 1. 添加定时任务
    void AddTimer(uint64_t id, uint32_t delay, const TaskFunc& cb);
    // 2. 刷新/延迟 定时任务
    void RefreshTimer(uint64_t id);
    // 3. 取消定时任务
    void CancelTimer(uint64_t id);

        
    /*这个接口存在线程安全问题--这个接口实际上不能被外界使用者调用，只能在模块内，在对应的EventLoop线程内执行*/
    bool HasTimer(uint64_t id) {
        auto it = _timers.find(id);
        if(it == _timers.end()) return false;
        return true;
    }

private:
    int _tick; // 当前指针, 走到哪释放哪(相当于执行哪里任务)
    int _capacity; // 定时器轮的大小 -- 最大延迟时间
    std::vector<std::vector<PtrTask>> _wheel; // 定时器轮
    std::unordered_map<uint64_t, WeakTask> _timers; // 定时器任务 id 和定时器对象的映射关系

    EventLoop* _loop; // 事件循环
    int _timerfd; // 定时器文件描述符 -- 可读事件回调 读取计数器, 执行定时任务
    std::unique_ptr<Channel> _timer_channel; // 定时器通道
};


